//
//  GBFileManager.h
//  PngOK
//
//  Created by wanglidong on 14-5-5.
//  Copyright (c) 2014年 GoldenBull. All rights reserved.
//

#import <Foundation/Foundation.h>

#define GBFileManager_Allload 0 // 是否加载所有接口

typedef enum : NSUInteger {
    GBFileTypeNone = 0,
    GBFileTypeFile,
    GBFileTypeFolder,
} GBFileType;

@interface GBFileManager : NSObject

/**
 * 获取文件大小
 * @param path 文件全路径
 */
+ (unsigned long long)fileSizeOfItemAtPath:(NSString *)path;

/** 检查是目录还是文件
 *
 * @param path 目录全路径
 *
 * @return item类型
 */
+ (GBFileType)typeOfItemAtPath:(NSString *)path;

/** 检查是否存在文件或目录
 *
 * @param path 目录全路径
 * @param isDirectory path是否为目录
 *
 * @return 存在 YES / 否则 NO
 */
+ (BOOL)isExist:(NSString *)path isDirectory:(BOOL)isDirectory;

/***************************************************************
 同一目录下, 无法同时存在同名的文件和目录, 为保证正确创建, 采用了以下规则:
 1. newFoler 会删除同名的file
 2. newFile  会删除同名的folder
 **************************************************************/

/** 新建目录
 *
 * @param path 目录全路径
 * @param shouldForce 是否强制新建, 强制新建会先删除已存在的目录(包括其子目录, 慎用!!!), 再新建.
 *
 * @return 目录创建成功 YES / 否则 NO
 */
+ (BOOL)newFolder:(NSString *)path force:(BOOL)shouldForce NS_AVAILABLE(10_5, 2_0);
// 通常newFoler是不会失败的, 失败时想要查看原因使用下面的接口.
+ (BOOL)newFolder:(NSString *)path error:(NSError **)error force:(BOOL)shouldForce NS_AVAILABLE(10_5, 2_0);

/** 新建文件
 *
 * @param path 文件全路径
 * @param shouldForce 是否强制新建, 强制新建会先删除已存在的文件, 再新建.
 *
 * @return 文件创建成功 YES / 否则 NO
 */
+ (BOOL)newFile:(NSString *)path force:(BOOL)shouldForce NS_AVAILABLE(10_5, 2_0);

/** 拷贝文件(夹)
 *
 * 目标路径(及其上级目录)如果不存在, 会自动创建
 *
 * @param srcPath 文件(夹)源路径
 * @param dstPath 文件(夹)目标路径
 * @param shouldForce 是否强制拷贝, 强制拷贝会先删除目标路径已存在的文件(夹), 再拷贝.
 *
 * @return 复制成功 YES / 否则 NO
 */
+ (BOOL)copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath force:(BOOL)shouldForce NS_AVAILABLE(10_5, 2_0);
// 失败时想要查看原因使用下面的接口.
+ (BOOL)copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error NS_AVAILABLE(10_5, 2_0);

/** 移动文件(夹)
 *
 * 参考 copyItemAtPath, 唯一区别是会删除源路径 srcPath
 *
 */
+ (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath force:(BOOL)shouldForce NS_AVAILABLE(10_5, 2_0);
// 失败时想要查看原因使用下面的接口.
+ (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error NS_AVAILABLE(10_5, 2_0);

/** 删除文件(夹)
 *
 * 会先检查目标路径是否存在
 *
 * @param path 文件(夹)全路径
 *
 * @return 删除成功 YES / 否则 NO
 */
+ (BOOL)removeItemAtPath:(NSString *)path NS_AVAILABLE(10_5, 2_0);
// 失败时想要查看原因使用下面的接口.
+ (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error NS_AVAILABLE(10_5, 2_0);

#pragma mark -
#pragma mark 不常用的接口
#if GBFileManager_Allload

/** 设置文件属性:修改时间
 *
 * @param date 更新时间
 *
 * @param path 文件（夹）全路径
 *
 * @return 设置成功 YES / 否则 NO
 */
+ (BOOL)setModifyTime:(NSDate *)date ofItemAtPath:(NSString *)path NS_AVAILABLE(10_5, 2_0);
// 失败时想要查看原因使用下面的接口.
+ (BOOL)setModifyTime:(NSDate *)date ofItemAtPath:(NSString *)path  error:(NSError **)error NS_AVAILABLE(10_5, 2_0);

/** 计算一个目录的总大小
 *
 * @param path 目录全路径
 *
 * @return 目录大小, 单位: 字节
 */
+ (long long)sizeOfFolder:(NSString *)path;


/** 设备磁盘总大小
 */
+ (long long)deviceTotalSize NS_AVAILABLE(10_5, 2_0);

/** 设备磁盘剩余空间大小
 */
+ (long long)deviceFreeSize NS_AVAILABLE(10_5, 2_0);

#pragma mark - file/folder
/** 获取目录下的所有项目，包括文件夹和文件
 *
 * @param path 目录全路径
 *
 * @return 文件（夹）列表
 */
+ (NSArray *)childrenAtPath:(NSString *)path;

/** 获取目录下的所有有效文件
 *
 * @param path 目录全路径
 *
 * @return 文件列表
 */
+ (NSArray *)filesAtPath:(NSString *)path;

/** 删除文件
 *
 */
+ (BOOL)removeFileAtPath:(NSString *)path NS_AVAILABLE(10_5, 2_0);
+ (BOOL)removeFileAtPath:(NSString *)path error:(NSError **)error NS_AVAILABLE(10_5, 2_0);

/** 删除文件夹
 *
 */
+ (BOOL)removeFolderAtPath:(NSString *)path NS_AVAILABLE(10_5, 2_0);
// 失败时想要查看原因使用下面的接口.
+ (BOOL)removeFolderAtPath:(NSString *)path error:(NSError **)error NS_AVAILABLE(10_5, 2_0);


/** 生成一个写入流
 *
 * @param path 文件全路径
 * @param shouldAppend 是否将新内容追加到原有文件结尾
 *
 * @return 写入流
 */
+ (NSOutputStream *)outputStreamToFileAtPath:(NSString *)path append:(BOOL)shouldAppend NS_AVAILABLE(10_5, 2_0);


#endif
@end

#pragma mark -
#pragma mark c/c++ 接口
/******************************************************
 * 储存单位
 ******************************************************/
#define GB_STORAGE_ARY 1024                        // 进制
#define GB_STORAGE_KB 1024                         // 1KB
#define GB_STORAGE_MB (1024 * 1024)                // 1MB
#define GB_STORAGE_GB (1024 * 1024 * 1024)         // 1GB
// 字节转字符串
#define SizeFormat_B		@"%0.0fB"
#define SizeFormat_KB		@"%0.0fKB"
#define SizeFormat_MB		@"%0.1fMB"
#define SizeFormat_GB		@"%0.1fGB"
NSString* stringWithSizeAllowB(double size);
NSString* stringWithSizeAvoidZero(double size);

/**
 * 遍历寻找文件
 * @param rootPath   搜索根目录
 * @param folderPath 当前搜索目录
 * @param ext        扩展名
 * @param files      结果集合
 */
void filesHasExtension(NSString *rootPath, const char *folderPath, NSString *ext, NSMutableArray *files, double *totalSize);

/**
 * 添加文件到集合
 * @param rootPath   搜索根目录
 * @param folderPath 当前搜索目录
 * @param name       文件名
 * @param size       文件大小
 * @param files      结果集合
 * @param totalSize  文件总大小
 */
void addFileToList(NSString *rootPath, NSString *path, NSString *name, off_t size, NSMutableArray *files, double *totalSize);
